package com.nulldev.util.data.Images.legacy;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import com.nulldev.util.VariableAPI.RandomUtil;
import com.nulldev.util.data.Variables;
import com.nulldev.util.data.Images.ColorUtil;
import com.nulldev.util.data.Images.ImageUtil;
import com.nulldev.util.data.legacy.CloneUtils;
import com.nulldev.util.gui.fontAPI.FontManager;
import com.nulldev.util.gui.swingAPI.Swing;

/**
 * TODO: Migrate this to the renderIt! API.
 */
public class TextObf {
	private static final String[] FONTS =
		{ "CommitMono", "Code New Roman", "Julia Mono", "Deja Vu Sans", "Roboto" };

	public static Font __font(final int size) {
		return FontManager.gets(FONTS).getFont(size);
	}

	public static Font __rand_font(final int size) {
		return FontManager.randGets(FONTS).getFont(size);
	}

	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * 
	 * @param text
	 * @return Obfuscated BufferedImage
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method) {
		return obfuscate(text, method, false, __font(16));
	}

	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * 
	 * @param text
	 * @return Obfuscated BufferedImage
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method, final Font font) {
		return obfuscate(text, method, false, font);
	}

	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * 
	 * @param text
	 * @return Obfuscated BufferedImage
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method, final boolean _imageboardformatting) {
		return obfuscate(text, method, _imageboardformatting, FontManager.getFontSetAsAWT());
	}

	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * <s>Method: Random Pixels</s>
	 * 
	 * @param text
	 * @return Obfuscated BufferedImage or null if no method provided
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method, final boolean _imageboardformatting, final Font font) {
		Variables.requireNonNull(text, "text");
		Variables.requireNonNull(method, "method");
		Variables.requireNonNull(font, "font");
		BufferedImage pre = ImageUtil.createFromColorImg(Color.WHITE, 256, 128);
		final Graphics g0 = pre.getGraphics();
		g0.setFont(font);
		((Graphics2D) g0).setRenderingHint(RenderingHints.KEY_ANTIALIASING, Swing.autoAAHint());
		final String[] lines = text.split("\n");
		final int height = (int) Math.floor((lines.length * (font.getSize() * 1.25)));
		int longest = 0;
		for (final String line : lines) {
			final int length = (int) (Swing.stringWidth(g0.getFontMetrics(), line) * 1.6) + g0.getFontMetrics().getMaxAscent()
					+ g0.getFontMetrics().getMaxDescent();
			if (longest == 0) {
				longest = (int) (length + (g0.getFont().getSize() * 1.8));
			} else {
				if (longest > length) {
					longest = (int) (length + (g0.getFont().getSize() * 1.6));
				}
			}
		}
		g0.dispose();
		pre = ImageUtil.createFromColorImg(Color.WHITE, longest, height);
		final Graphics g = pre.getGraphics();
		((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, Swing.autoAAHint());
		if (method == ObfuscationMethod.RainbowBackground || method == ObfuscationMethod.RainbowBackgroundNoise
				|| method == ObfuscationMethod.RainbowBackgroundPixels) {
			for (int i = 0; i < (longest / 80); i++) {
				g.setColor(ColorUtil.rainbow(60000000L * i, RandomUtil.randFloat(.4f, .9f)));
				g.fillRect(i * 80, 0, 80, height);
			}
		}
		g.setFont(font);
		final Color DEFAULT_COLOR = (method == ObfuscationMethod.Noise ? ColorUtil.randomColor() : Color.BLACK);
		g.setColor(DEFAULT_COLOR);
		int y = (int) (Math.floor(font.getSize2D())) - 5;
		for (final String line : lines) {
			if (_imageboardformatting) {
				if (line.startsWith(">") && !line.startsWith(">>")) {
					g.setColor(Color.WHITE);
					g.drawString(text, 6, y + 1);
					g.setColor(ColorUtil.GREEN);
					g.drawString(line, 7, y);
					g.setColor(DEFAULT_COLOR);
				} else if (line.startsWith(">>")) {
					g.setColor(Color.WHITE);
					g.drawString(text, 6, y + 1);
					g.setColor(Color.RED);
					g.drawString(line, 7, y);
					g.setColor(DEFAULT_COLOR);
				} else {
					g.setColor(Color.WHITE);
					g.drawString(text, 6, y + 1);
					g.setColor(DEFAULT_COLOR);
					g.drawString(line, 7, y);
				}
			} else {
				g.setColor(Color.WHITE);
				g.drawString(text, 6, y + 1);
				g.setColor(DEFAULT_COLOR);
				g.drawString(line, 7, y);
			}
			y += 15;
		}
		g.dispose();
		return obf(method, pre);
	}

	public static BufferedImage obfuscateImage(final BufferedImage image, final ObfuscationMethod method) {
		return obf(method, image);
	}

	private static BufferedImage obf(final ObfuscationMethod method, final BufferedImage pre) {
		Variables.requireNonNull(method, "method");
		Variables.requireNonNull(pre, "pre");
		switch (method) {
			case RainbowBackground:
			case None: {
				return pre;
			}
			case V2_EXPERIMENT_ONE: {
				final BufferedImage obf = CloneUtils.deepCopy(pre);
				final Graphics go = obf.getGraphics();
				for (int y = 0; y < obf.getHeight(); y++) {
					for (int x = 0; x < obf.getWidth(); x++) {
						go.setColor(ColorUtil.randomGray(85));
						go.drawRect(x, y, 1, 1);
					}
				}
				return obf;
			}
			case PixelObfuscation:
			case RainbowBackgroundPixels: {
				final BufferedImage obf = CloneUtils.deepCopy(pre);
				final Graphics go = obf.getGraphics();
				for (int i = 0; i < obf.getWidth() / 2; i++) {
					go.setColor(ColorUtil.randomColor());
					go.drawRect(RandomUtil.randInt(0, obf.getWidth()), RandomUtil.randInt(0, obf.getHeight()), 1, 1);
				}
				go.dispose();
				return obf;
			}
			case DualPixelObfuscation: {
				final BufferedImage obf = CloneUtils.deepCopy(pre);
				final Graphics go = obf.getGraphics();
				for (int i = 0; i < obf.getWidth() / 2; i++) {
					go.setColor(ColorUtil.randomColor());
					go.drawRect(RandomUtil.randInt(0, obf.getWidth()), RandomUtil.randInt(0, obf.getHeight()), 1, 1);
				}
				for (int i = 0; i < obf.getWidth() / 2; i++) {
					go.setColor(ColorUtil.randomColor());
					go.drawRect(RandomUtil.randInt(0, obf.getWidth()), RandomUtil.randInt(0, obf.getHeight()), 1, 1);
				}
				go.dispose();
				return obf;
			}
			case Noise:
			case RainbowBackgroundNoise: {
				final BufferedImage obf = CloneUtils.deepCopy(pre);
				for (int x = 0; x < obf.getWidth(); x++) {
					for (int y0 = 0; y0 < obf.getHeight(); y0++) {
						final Color t = new Color(obf.getRGB(x, y0));
						if (t != Color.BLACK) {
							obf.setRGB(x, y0, obf.getRGB(x, y0) + RandomUtil.randInt(1, 6000));
						}
					}
				}
				return obf;
			}
			case PixelsAndNoise: {
				final BufferedImage obf = CloneUtils.deepCopy(pre);
				for (int x = 0; x < obf.getWidth(); x++) {
					for (int y0 = 0; y0 < obf.getHeight(); y0++) {
						final Color t = new Color(obf.getRGB(x, y0));
						if (t != Color.BLACK) {
							obf.setRGB(x, y0, obf.getRGB(x, y0) + RandomUtil.randInt(1, 6000));
						}
					}
				}
				final Graphics go = obf.getGraphics();
				for (int i = 0; i < obf.getWidth() / 2; i++) {
					go.setColor(ColorUtil.randomColor());
					go.drawRect(RandomUtil.randInt(0, obf.getWidth()), RandomUtil.randInt(0, obf.getHeight()), 1, 1);
				}
				go.dispose();
				return obf;
			}
			default:
				throw new UnsupportedOperationException("Unknown method: " + method);
		}
	}

	public static enum ObfuscationMethod {
		/* v1 */
		PixelObfuscation,
		DualPixelObfuscation,
		Noise,
		PixelsAndNoise,
		None,
		RainbowBackground,
		RainbowBackgroundNoise,
		RainbowBackgroundPixels,

		/* v2 */
		V2_EXPERIMENT_ONE,
	}
}
